<template>
  <div class="form-setting-panel form-video-setting-panel">
    <mform-setting-title title="视频">
    </mform-setting-title>
    
    <mform-setting-title-name 
      ref="MFormSettingTitle" 
      :value="value" 
      @input="updateTitle"
      :language-list="languageList"
      :is-open-multi-language="isOpenMultiLanguage"
    >
    </mform-setting-title-name>
    
    <mform-setting-description-name 
      ref="MFormSettingDescription" 
      :value="value" 
      @input="updateDescription"
      :language-list="languageList"
      :is-open-multi-language="isOpenMultiLanguage"
    >
    </mform-setting-description-name>
    
    <mform-setting-divider />
    
    <mform-item ref='UploadFieldItem' :prop-field="uploadField" :label="uploadField.displayName" :validation="validation">
      <div class="form-video-setting-panel-tip form-video-setting-panel-tip-first">
        最多可添加5个视频，建议视频宽高比为16:9，大小不超过200M，视频可拖动排序
      </div>
    </mform-item>
    
    <div class="form-video-setting-panel-upload">
      <draggable
        animation="180"
        class="nested-draggable"
        tag="div" 
        :list="value.videoList"
        filter=".undraggable"
        @end="draggableEndHandler"
      >
        <div class="video-item" v-for="(item, index) in value.videoList" :key="item.url">
          
          <div class="mform-setting-video-list-item-header">
            <span class="mform-setting-video-list-item-header-title">
              视频 {{ index + 1}}
            </span>
            <span class="mform-setting-video-list-item-header-delete" @click="deleteItem(index)">
              删除
            </span>
          </div>
          
          <div class="form-video-setting-video-item-content">
            
            <div class="form-video-setting-video-item-content-image-block">
              
              <el-upload 
                action="string"
                :on-preview="handlePictureCardPreview"
                :before-upload="onBeforeUploadImage"
                :http-request="uploadImagePicBefore(index)"
                :limit="10000"
                accept=".jpg,.jpeg,.png"
              >
                <mform-setting-mark text="更换封面" v-if="item.videoUrl">
                  <img v-if="item.videoUrl" :src="getVideoFullUrl(item)" class="avatar" alt="视频">
                </mform-setting-mark>
                <i class="el-icon-plus" v-else></i>
              </el-upload>
              
              <!-- <span class="upload-list__item-actions">
                <span class="upload-list__item-preview">
                  <i class="el-icon-zoom-in"></i>
                </span>
                <span class="upload-list__item-delete">
                  <i class="el-icon-delete"></i>
                </span>
              </span> -->
            </div>
            
            <div class="form-video-setting-video-item-content-right">
              <div class="form-video-setting-video-item-content-source"> 来源：{{ getSource(item) }} </div>
              <div class="link-text form-video-setting-video-item-content-play" @click="play(item)">
                播放
              </div>
            </div>
            
          </div>
          
        </div>
      </draggable>
    </div>
    
    <el-dropdown @command="handleCommand" v-if="isShowAddVideoButton" trigger="click" placement="bottom">
      <el-button
        :icon="videoLoading ? '' : 'el-icon-plus'"
        :loading="videoLoading"
        class="mform-setting-add-button"
        plain
        type="primary"
      >
        {{ videoLoading ? '正在上传' : '添加' }}
      </el-button>
      <el-dropdown-menu slot="dropdown">
        <el-dropdown-item command="local">本地上传</el-dropdown-item>
        <el-dropdown-item>粘贴视频地址</el-dropdown-item>
      </el-dropdown-menu>
    </el-dropdown>
    
    <template>
      <el-upload
        v-show="false"
        action="string"
        ref="upload"
        accept="video/mp4"
        list-type="picture-card"
        :on-preview="handleVideoPreview"
        :before-upload="onBeforeUploadVideo"
        :http-request="UploadVideo"
        :on-change="fileChange"
        :limit="10"
      >
        <i class="el-icon-plus"></i>
      </el-upload>
    </template>
    
    <!-- 提示框 -->
    <base-modal :show.sync="visible" title="粘贴视频地址" class="form-video-url-modal">
      <div class="modal-box">
        <mform-item :label="videoUrlField.displayName" ref="VideoUrlFormItem" :validation="validationVideoUrl">
          <form-text :value="videoUrl" :field="videoUrlField" @input="videoUrlChange" />
        </mform-item>
      </div>
      <div class="flex-x" slot="footer">
        <el-button type="ghost" @click="cancel">取消</el-button>
        <el-button type="primary" @click="addVideoUrl">确定</el-button>
      </div>
    </base-modal>
    
    <template v-if="showVideo">
      <video
        v-show="false"
        @loadeddata="createPreImg($event)"
        class="content-video"
        :src="videoUrl"
        crossorigin="anonymous"
        preload="auto"
      />
    </template>
    
  </div>
</template>

<script>
/* component */
import draggable from 'vuedraggable'
/* model */
import { 
  FormVideoSettingSourceField, 
  FormTitleSettingCoverImageField,
  FormVideoSettingUploadField,
  FormTitleSettingUploadCoverField,
  FormVideoSettingVideoUrlField
} from '@src/mform/components/FormVideo/FormVideoModel.ts'
/* mixin */
import SettingMixin from '@src/mform/mixin/setting'
/* props */
import { settingProps } from '@src/mform/components/props'
/* util */
import * as FormUtil from '@src/component/form/util'
import _ from 'lodash'
import Uploader from 'packages/BaseUpload/uploader'
import { isEmpty } from '@src/util/type'
/* constant */
const LINK_REG = /^https?:\/\/(.+\/)+.+(\.(mp4))$/i
import { safeNewDate } from '@src/util/time';

export default {
  name: 'mform-video-setting',
  inject: ['addNeedServerDeleFiles'],
  mixins: [SettingMixin],
  props: settingProps,
  data() {
    return {
      visible: false,
      videoUrl: '',
      showVideo: false,
      pasteVideoPlay: false,
      videoListLength: 0,
      videoLoading: false
    }
  },
  computed: {
    isLocalUpload() {
      return this.value.type == '本地上传'
    },
    isOriginCoverImage() {
      return this.value.coverImageType == '原视频封面'
    },
    sourceField() {
      return FormVideoSettingSourceField
    },
    coverImageField() {
      return FormTitleSettingCoverImageField
    },
    uploadField() {
      return FormVideoSettingUploadField
    },
    uploadCoverField() {
      return FormTitleSettingUploadCoverField
    },
    videoUrlField() {
      return FormVideoSettingVideoUrlField
    },
    settingFields() {
      return [this.sourceField, this.coverImageField]
    },
    value() {
      let videoList = this.fieldSetting.videoList || [];
      return {
        ...this.commonSettingValue,
        videoList
      }
    },
    isVideosEmpty() {
      return isEmpty(this.value.video)
    },
    isVidesMax() {
      return this.value.videoList.length >= 5
    },
    isShowAddVideoButton() {
      return !this.isVidesMax
    }
  },
  methods: {
    handleVideoPreview(file) {
      const url = file?.response?.url ? file.response.url : file.url
      this.$previewVideo(url)
    },
    getVideoFullUrl(item) {
      return item.videoPicture
    },
    getSource(item) {
      return item.type == 'local' ? '本地上传' : '粘贴视频地址'
    },
    onBeforeUploadVideo (file) {
      const isMP4 = file.type === 'video/mp4';
      const isLimit200M = file.size / 1024 / 1024 < 200;
      
      if (!isMP4) {
        this.$message.error('上传视频只能是 mp4 格式!');
      }
      if (!isLimit200M) {
        this.$message.error('上传视频大小不能超过 200MB!');
      }
      
      if(isMP4 && isLimit200M){
        this.videoDisabled = true;
      }
      return isMP4 && isLimit200M;
    },
    UploadVideo(param) {
      this.videoLoading = true;
      return Uploader.upload(param.file, '/files/uploadVideo').then(res => {
        if (res.status == 0) {
          let item_ = {
            uid: param.file.uid,
            id: res.data.id,
            filename: res.data.fileName,
            name: res.data.fileName,
            // 如果后端返回url,必须使用。如果后端不返回，需要拼接
            url: res.data.ossUrl || res.data.url || `/files/get?fileId=${res.data.id}`,
            fileSize: res.data.fileSizeStr,
            type: 'local'
          }
          
          item_.videoUrl = item_.url
          item_.videoPicture = `${item_.url}?x-oss-process=video/snapshot,t_1000,f_jpg,w_800,h_600,m_fast`
          this.videoLoading = false;
          
          let videoList = _.cloneDeep(this.value.videoList)
          videoList.push(item_)
          this.updateVideoList(videoList)
        }
      })
    },
    updateVideosType(value) {
      this.update(value, 'uploadType')
    },
    updateCoveredImageType(value) {
      this.update(value, 'coverImageType')
    },
    // update(value, prop, isSetting = true) {
    //   this.$emit('input', { value, prop, isSetting });
    // },
    handlePictureCardPreview (file) {
      this.$previewElementImg(file.url)
    },
    onBeforeUploadImage (file) {
      const isJPG = file.type === 'image/jpeg' || file.type === 'image/png';
      const isLt2M = file.size / 1024 / 1024 < 2;
      
      if (!isJPG) {
        this.$message.error('上传图片只能是 jpg/png 格式!');
      }
      if (!isLt2M) {
        this.$message.error('上传图片大小不能超过 2mb!');
      }
      
      return isJPG && isLt2M;
    },
    uploadImagePic(param, index) {
      Uploader.upload(param.file, '/files/upload', { fileName: param.fileName })
        .then((result) => {
          if (result.status != 0) {
            this.$message({
              message: `${result.message}`,
              duration: 1500,
              type: 'error',
            });
            return;
          }
          
          let file = result.data;
          let item = {
            uid: param.file.uid,
            id: file.id,
            filename: file.fileName,
            // 如果后端返回url,必须使用。如果后端不返回，需要拼接
            url: file.ossUrl || file.url || `/files/get?fileId=${file.id}`,
            fileSize: file.fileSizeStr,
          }
          
          let lists = _.cloneDeep(this.value.videoList)
          lists[this.videoListLength] = {
            videoUrl: this.videoUrl,
            videoPicture: item.url,
            type: 'remote'
          }
          
          this.updateVideoList(lists)
        })
        .catch((err) => {
          console.warn(err)
        })
        .finally(() => { 
          // 
        })
    },
    fileChange(file) {
      // 清除文件对象
      this.$refs.upload.clearFiles();
    },
    clickUpdate() {
      this.$refs.upload.$children[1].$refs.input.click();
    },
    handleCommand(command) {
      if (command == 'local') {
        return this.clickUpdate()
      }
      
      this.visible = true
    },
    videoUrlChange(value) {
      // https://file.shb.ltd/acs/newfiles/7416b42a-25cc-11e7-a500-00163e12f748/202109/12a6c0bf-e312-4d1f-883f-cb2bbe090629.mp4
      this.videoUrl = value
    },
    cancel() {
      this.visible = false
    },
    validateUrl() {
      return LINK_REG.test(this.videoUrl)
    },
    validationVideoUrl(){
      return new Promise((resolve, reject) => {
        if(!this.validateUrl()) {
          return resolve('请输入正确的视频链接');
        }
        
        resolve(null);
      })
    },
    addVideoUrl() {
      if (!this.validateUrl()) {
        return this.$refs.VideoUrlFormItem.validate()
      }
      
      this.videoListLength = this.value.videoList.length;
      this.showVideo = true;
      
      let videoList = _.cloneDeep(this.value.videoList)
      videoList.push({
        videoUrl: this.videoUrl,
        videoPicture: '',
        type: 'rremote'
      })
      
      this.updateVideoList(videoList)
      this.visible = false
      
      this.$nextTick(() => {
        this.showVideo = false
      })
    },
    updateVideoList(value) {
      this.update(value, 'videoList')
      this.$nextTick(() => {
        this.validateVideo()
        this.updateErrorStatus(false)
      })
    },
    deleteItem(index) {
      let lists = _.cloneDeep(this.value.videoList)
      this.addNeedServerDeleFiles([lists[index].id], false)
      lists.splice(index, 1)
      this.updateVideoList(lists)
    },
    play(item) {
      let url = item.videoUrl || item.url
      this.$previewVideo(url)
    },
    draggableEndHandler() {
      this.$nextTick(() => {
        this.updateVideoList(_.cloneDeep(this.value.videoList))
      })
    },
    uploadImagePicBefore(index) {
      return (params) => {
        this.uploadImagePicture(params, index)
      }
    },
    validation(){
      return new Promise((resolve, reject) => {
        if(!this.value.videoList || isEmpty(this.value.videoList)) {
          return resolve('请上传视频');
        }
        
        resolve(null);
      })
    },
    uploadImagePicture(param, index) {
      Uploader.upload(param.file, '/files/upload')
        .then((result) => {
          if (result.status != 0) {
            this.$message({
              message: `${result.message}`,
              duration: 1500,
              type: 'error',
            });
            return;
          }
          
          let file = result.data;
          let item = {
            uid: param.file.uid,
            id: file.id,
            filename: file.fileName,
            // 如果后端返回url,必须使用。如果后端不返回，需要拼接
            url: file.ossUrl || file.url || `/files/get?fileId=${file.id}`,
            fileSize: file.fileSizeStr,
          }
          
          let lists = _.cloneDeep(this.value.videoList)
          this.addNeedServerDeleFiles([lists[index].videoPicture], false)
          lists[index].videoPicture = item.url;
          this.updateVideoList(lists)
        })
        .catch((err) => {
          console.warn(err)
        })
        .finally(() => { 
          // 
        })
    },
    createPreImg(event) {
      const that = this;
      // 当前video dom节点
      const videoEle = event.target;
      
      // 设置视频开始播放时间（因为有些手机第一帧显示黑屏，所以这里选取视频的第一秒作为封面）
      videoEle.currentTime = 1;
      
      videoEle.addEventListener('canplay', function () {
        if (that.pasteVideoPlay) return
        
        that.pasteVideoPlay = true
        
        // 创建canvas元素 并设置canvas大小等于video节点的大小
        const canvas = document.createElement('canvas');
        const scale = 1; // 压缩系数
        canvas.width = videoEle.videoWidth * scale;
        canvas.height = videoEle.videoHeight * scale;
        
        // canvas画图
        canvas.getContext('2d').drawImage(videoEle, 0, 0, canvas.width, canvas.height);
        
        // 把canvas转成base64编码格式
        const imgSrc = canvas.toDataURL('image/png');
        
        // 创建img元素 插入到文档中
        const img = document.createElement('img');
        img.src = imgSrc;
        img.style.position = 'absolute';
        img.style.left = '0';
        img.style.top = '0';
        img.style.objectFit = 'cover';
        // videoEle.parentNode && videoEle.parentNode.appendChild(img);
        
        // 将base64转换为blob
        const dataURLtoBlob = function(dataurl) { 
          let arr = dataurl.split(',');
          let mime = arr[0].match(/:(.*?);/)[1];
          let bstr = atob(arr[1]);
          let n = bstr.length;
          let u8arr = new Uint8Array(n);
          while (n--) {
            u8arr[n] = bstr.charCodeAt(n);
          }
          return new Blob([u8arr], { type: mime });
        }
        
        // 将blob转换为file
        const blobToFile = function(theBlob, fileName){
          theBlob.lastModifiedDate = safeNewDate();
          theBlob.name = fileName;
          theBlob.filename = fileName;
          return theBlob;
        }
        
        const fileName = `${that.videoUrl}.png`
        // 调用
        let blob = dataURLtoBlob(img.src);
        let file = blobToFile(blob, fileName);
        that.uploadImagePic({ file, fileName })
        
        that.$nextTick(() => {
          that.pasteVideoPlay = false
        })
        
      });
    },
    captureImage(url) {
      let that = this;
      // 创建视频对象
      let video = document.createElement('video');
      video.width = 1000;
      video.height = 1000;
      video.setAttribute('crossOrigin', 'Anonymous');
      video.setAttribute('controls', 'controls');
      video.setAttribute('autoplay', 'autoplay');
      video.volume = 0;
      video.currentTime = 1
      video.setAttribute('src', url); // 视频的链接
      
      video.onloadedmetadata = function() {
        // 创建canvas画布
        let canvas = document.createElement('canvas');
        // 设置画布的长宽也就是图片的长宽
        canvas.width = video.width;
        canvas.height = video.height;
        canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
        let img = document.createElement('img');
        img.setAttribute('crossOrigin', 'Anonymous');
        img.src = canvas.toDataURL('image/png');
        
        let name = img.src.substring(img.src.lastIndexOf('/') + 1, img.src.length);
        
        that.dataURLtoFile(img.src, `${that.videoUrl}.png`);
      }
      
      video.onloadeddata = function() {
        // 创建canvas画布
        let canvas = document.createElement('canvas');
        // 设置画布的长宽也就是图片的长宽
        canvas.width = video.width;
        canvas.height = video.height;
        canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
        let img = document.createElement('img');
        img.setAttribute('crossOrigin', 'Anonymous');
        img.src = canvas.toDataURL('image/png');
        
        let name = img.src.substring(img.src.lastIndexOf('/') + 1, img.src.length);
        
        that.dataURLtoFile(img.src, `${that.videoUrl}.png`);
      }
    },
    dataURLtoFile(dataurl, filename) {
      let arr = dataurl.split(',');
      let mime = arr[0].match(/:(.*?);/)[1];
      let bstr = atob(arr[1]);
      let n = bstr.length;
      let u8arr = new Uint8Array(n);
      
      while (n--) {
        u8arr = bstr.charCodeAt(n);
      }
      
      let file = new File([u8arr], filename, {type: mime});
    }
  },
  components: {
    draggable
  }
};
</script>

<style lang="scss">
.form-video-setting-panel {
  .form-item {
    padding: 0 16px;
    & > label {
      width: 80px;
      padding-left: 0;
    }
  }
  .form-item-control {
    max-width: calc(100% - 80px);
  }
  .form-video-setting-panel-tip {
    line-height: 20px;
    color: #8C8C8C;
    font-size: 12px;
  }
  .form-video-setting-panel-tip-first {
    padding-top: 4px;
  }
  .el-upload-list__item {
    display: none;
  }
  .el-dropdown {
    width: 100%;
  }
}

.video-item {
  position: relative;
  height: 56px;
  width: 100px;
  .upload-list__item-actions {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    display: none;
    width: 100%;
    height: 100%;
  }
  &:hover {
    .upload-list__item-actions {
      background-color: rgba(0, 0, 0, .5);
      color: #fff;
      display: block;
    }
  }
  .upload-list__item-preview {
    cursor: pointer;
    position: absolute;
    top: 50%;
    left: 30px;
    transform: translateY(-50%)
  }
  .upload-list__item-delete {
    cursor: pointer;
    position: absolute;
    top: 50%;
    right: 30px;
    transform: translateY(-50%)
  }
  img {
    width: 100%;
    height: 100%;
  }
}

.form-video-setting-panel-upload {
  display: flex;
  flex-flow: column;
  padding-bottom: 16px;
  .el-upload {
    width: 100px;
    height: 56px;
    line-height: 56px;
  }
  .video-item {
    // margin-top: 12px;
    margin-right: 12px;
  }
}

.form-video-setting-panel-origin-tip {
  padding: 3px 16px;
}

.form-video-setting-panel-paste-input {
  padding: 8px 16px 24px 21px;
}

.form-video-setting-panel-upload-cover {
  .el-upload {
    width: 100px;
    height: 56px;
    line-height: 56px;
    margin-top: 12px;
    border: 1px dotted #D9D9D9;
    background-color: #f5f5f5;
  }
}

.form-video-url-modal {
  .base-modal-body {
    padding: 20px;
    .form-item {
      label {
        width: 110px;
      }
    }
  }
  input {
    height: 32px;
  }
}

.form-design-setting.mform-design-setting {
  .form-setting-panel.form-video-setting-panel {
    // .mform-setting-add-button {
    //   background-color: $color-primary-light-1 !important;
    //   border-color: $color-primary-light-3 !important;
    //   color: $color-primary !important;
    //   &:hover {
    //     border-color: $color-primary !important;
    //     background-color: $color-primary !important;
    //     color: #fff !important;
    //   }
    // }
    .mform-setting-add-button {
      // margin-top: 24px;
      margin-left: 16px;
      margin-right: 16px;
      width: calc(100% - 32px);
      height: 40px;
    }
  }
}

.mform-setting-video-list-item {
  background-color: #fafafa;
  &-header {
    display: flex;
    justify-content: space-between;
    line-height: 42px;
    &-title {
      color: #BFBFBF;
    }
    &-delete {
      cursor: pointer;
      color: #8C8C8C;
      &:hover {
        color: $color-danger;
      }
    }
  }
}

.form-video-setting-panel-upload {
  .video-item {
    width: 100%;
    height: 110px;
    padding-left: 32px;
    &:hover {
      background-color: #fff;
    }
  }
}

.form-video-setting-video-item-content {
  position: relative;
  display: flex;
  .upload-list__item-actions,
  .form-video-setting-video-item-content-image-block {
    height: 56px;
    width: 100px;
  }
  .form-video-setting-video-item-content-right {
    flex: 1;
    padding-left: 24px;
  }
  .form-video-setting-video-item-content-source {
    color: #595959;
  }
  .form-video-setting-video-item-content-play {
    margin-top: 16px;
  }
}
</style>
